In [1]:
import numpy as np
import math
import plotly.graph_objects as go
from plotly.subplots import make_subplots
In [2]:
n = 32
k = 1
p=0.25
def have_at_least_x_slots(p, k=1):
    p_sum = 0 
    for i in range(k, n+1):
        binomial_coefficient = math.factorial(n) / (math.factorial(i) * math.factorial(n-i))
        p_i = binomial_coefficient * (p**i) * ((1-p)**(n-i))
        p_sum += p_i
    return p_sum

def cum_prob_dist(p):
    p_cum_sum = []
    k=0
    for i in range(k, n+1):
        binomial_coefficient = math.factorial(n) / (math.factorial(i) * math.factorial(n-i))
        p_i = binomial_coefficient * (p**i) * ((1-p)**(n-i))
        p_cum_sum.append(p_i)
    return p_cum_sum
In [3]:
def draw_probability(_y):
    fig = make_subplots(specs=[[{"secondary_y": True}]])
    for ix, (y, name) in enumerate(_y):
        dash = "dot" if ix > 1 else "dash" if ix == 1 else "solid"
        x = list(range(0, len(y)))
        fig.add_trace(
            go.Scatter(x=x, y=y, mode='lines', name=f"prob. dist. {name}", line = dict(width=3, dash=dash)),  
            secondary_y=False
        )
        fig.add_trace(
            go.Scatter(x=x, y=np.cumsum(y), mode='lines', name=f"cum. prob. dist. {name}", line = dict(width=3, dash=dash)), 
            secondary_y=True
        )
    fig.update_layout(
        xaxis_title='Slots',
        legend=dict(x=0.7, y=0.9),
        width = 900,
        height = 350,
        margin=dict(l=0, r=0, t=0, b=0),
        xaxis=dict(
            showgrid=True,
            gridwidth=1,
            gridcolor='white',
            title_font=dict(size=18)
        ),
        yaxis=dict(
            title='Probability', 
            color='blue',
            showgrid=True,
            gridwidth=1,
            gridcolor='white',
            title_font=dict(size=18)
        ),
        yaxis2=dict(
            title='Cumulative Probability', 
            color='red', 
            overlaying='y', 
            side='right',
            showgrid=True,
            gridwidth=1,
            gridcolor='white',
            title_font=dict(size=18)
        ),
        font=dict(
            size=16
        ),
    )
                      
    return fig

y_25 = cum_prob_dist(0.25)
y_10 = cum_prob_dist(0.10)
y_50 = cum_prob_dist(0.50)
fig = draw_probability([(y_25, "25%"), (y_10, "10%"), (y_50, "50%")])
fig.write_image("probability_dist.png")
fig.show()
In [4]:
games = list(range(1, 21)) 
p = .25

def continue_biasing(p):
    probabilities = [] 
    for n in games:
        k = 0
        comb = math.comb(n, k)
        P_X_equals_0 = comb * (p**k) * ((1-p)**(n-k))
        P_X_geq_1 = 1 - P_X_equals_0

        probabilities.append(P_X_geq_1)
    return probabilities

probabilities_13 = continue_biasing(have_at_least_x_slots(p, 13)) # get 12 slots
probabilities_12 = continue_biasing(have_at_least_x_slots(p, 12)) # get 12 slots
probabilities_11 = continue_biasing(have_at_least_x_slots(p, 11)) # get 11 slots
probabilities_10 = continue_biasing(have_at_least_x_slots(p, 10)) # get 10 slots
probabilities_09 = continue_biasing(have_at_least_x_slots(p, 9))  # get 9 slots

fig = go.Figure()
for probabilities, name in zip([probabilities_13, 
                                probabilities_12, 
                                probabilities_11, 
                                probabilities_10, 
                                probabilities_09
                               ], 
                               ["getting 13 slots", 
                                "getting 12 slots", 
                                "getting 11 slots", 
                                "getting 10 slots", 
                                "getting 9 slots"
                               ]):
    fig.add_trace(
        go.Scatter(x=games, y=probabilities, mode='lines+markers', name=name)
    )

for x, sl in zip([2, 4, 8, 16],[1,2,3,4]):
    fig.add_shape(
        type='line',
        x0=x, y0=0, x1=x, y1=1,
        line=dict(color='Red',dash="dash"),
    )
    fig.add_annotation(x=x+0.95, y=0.05,
                       text=f"Controlling<br>{sl} tail slots",
                       showarrow=False,
                       font=dict(size=11, color="black"),
                       bgcolor="white",
                       opacity=0.7,
                      )

fig.update_layout(
    title='Probability of getting X slots with 25% validator share',
    xaxis=dict(
        title='Number of Possibilities (randao_reveal vs. missed slot)', 
        titlefont=dict(size=18),
        tickvals=list(range(0,21, 2))
    ),
    yaxis=dict(title='Probability', titlefont=dict(size=18)),
    showlegend=True,
    width = 900,
    height = 400,
    margin=dict(l=0, r=0, t=50, b=0),
    legend=dict(font=dict(size=16)),
    font=dict(
        size=16
    ),
)
fig.write_image("probabilities.png")
fig.show()